
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.Threading;

namespace AtDevice
{
    public enum NetworkEnum
    {
        NoSignal,
        GprsNetwork,
        EdgeNetowrk,
        WcdmaNetwork,
        UmtsNetwork,
        HsdpaNetwork,
        HsupaNetwork,
        HspaNetwork
    }

    public class HuaweiHandler : ISpecialHandler, IHuaweiInterface
    {
        private AtDevice _device;
        private bool _closing = false;
        private Thread _thread;

        public event ModeChangedDelegate ModeChanged;
        public event FlowInfoDelegate FlowUpdated;
        public int FlowUpdateInterval {
            get { return (int)0; }
            set { ; }
        }

        public HuaweiHandler(AtDevice device)
        {
            _device = device;
            DeviceHandler.DeviceClosing += delegate {
                _closing = true;
                _thread.Join();
            };

            _thread = new Thread((ThreadStart)delegate {
                while(!_closing)
                {
                    Thread.Sleep(2000);
                    // execute an empty command to get flow data read from the device
                    _device.ExecuteCommand(new AtCommand(""));
                }
            });
            _thread.Start();
        }

        public bool IsSpecialLine(string line)
        {
            // Huawei specific metadata
            return line.StartsWith("^MODE")
                || line.StartsWith("^DSFLOWQRY")
                || line.StartsWith("^RSSI")
                || line.StartsWith("^BOOT")
                || line.StartsWith("^DSFLOWRPT");
        }

        public void HandleLine(string line)
        {
            switch (GetCommand(line))
            {
                // ^MODE:n,n indicates which type of network is used
                case "MODE":
                    ModeChanged(GetMode(line));
                    break;
                case "DSFLOWQRY":
                    break;
                // ^RSSI:n indicates the signal strength. ignore it here and use AT+CSQ instead
                case "RSSI":
                    break;
                // ^DSFLOWRPT:n,n,n,n,n,n,n gives information about transmitted data
                case "DSFLOWRPT":
                    HandleFlowInfo(line);
                    break;
                // ^BOOT:n,n,n,n,n
                case "BOOT":
                    break;
                default:
                    AtLogger.LogInfo("Unknown Huawei specific command: " + GetCommand(line));
                    break;
            }
        }

        private void HandleFlowInfo(string line)
        {
            try
            {
                /* Input format:
                 * ^DSFLOWRPT:n,n,n,n,n,n,n
                 */
                string[] items = line.Split(':')[1].Split(',');
                int uptime = Convert.ToInt32(items[0], 16);
                int ulSpeed = Convert.ToInt32(items[1], 16);
                int dlSpeed = Convert.ToInt32(items[2], 16);
                long ulBytes = Convert.ToInt64(items[3], 16);
                long dlBytes = Convert.ToInt64(items[4], 16);

                if(FlowUpdated != null)
                    FlowUpdated(uptime, dlSpeed, ulSpeed, dlBytes, ulBytes);
            }
            catch (Exception ex) {
                AtLogger.LogInfo("Invalid line received: " + line);
                AtLogger.LogInfo(ex.ToString());
            }
        }

        private static NetworkEnum GetMode(string line)
        {
            switch (GetModeString(line))
            {
                case "0,0":
                    return NetworkEnum.NoSignal;
                case "3,0":
                    return NetworkEnum.GprsNetwork;
                case "3,1":
                    return NetworkEnum.GprsNetwork;
                case "3,2":
                    return NetworkEnum.GprsNetwork;
                case "3,3":
                    return NetworkEnum.EdgeNetowrk;
                case "4,1":
                    return NetworkEnum.WcdmaNetwork;
                case "5,4":
                    return NetworkEnum.UmtsNetwork;
                case "5,5":
                    return NetworkEnum.HsdpaNetwork;
                case "5,6":
                    return NetworkEnum.HsupaNetwork;
                case "5,7":
                    return NetworkEnum.HspaNetwork;
            }

            AtLogger.LogInfo("Unknown network mode: " + GetModeString(line));

            return NetworkEnum.NoSignal;
        }

        private static string GetModeString(string line)
        {
            string[] splitted = line.Split(':');
            if (splitted.Length > 1)
                return splitted[1];

            return "0,0";
        }

        private static string GetCommand(string line)
        {
            string [] splitted = line.Split(':');
            if (splitted.Length > 0)
                return splitted[0].TrimStart('^');

            return "";
        }
    }
}
